package com.context;

import com.annotation.RD;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisKeyValueAdapter;
import org.springframework.data.redis.core.RedisKeyValueTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.mapping.RedisMappingContext;
import org.springframework.data.redis.repository.support.RedisRepositoryFactory;
import org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean;

import java.util.HashMap;
import java.util.Map;

/**
 * 动态redis数据源上下文对象
 *
 * @author wanghaicheng
 * @since 1.0.0
 */
@Data
public class DynamicRDBContext implements BeanPostProcessor {
    private static Map<String, RedisConnectionFactory> redisConnectionFactories = new HashMap<>();
    private static Map<String, RedisTemplate<?, ?>> templates = new HashMap<>();

    public static RedisConnectionFactory getRedisConnectionFactory(String dbName) {
        RedisConnectionFactory redisConnectionFactory = redisConnectionFactories.get(dbName);
        if (redisConnectionFactory == null) {
            throw new RuntimeException("操作数据库不存在,请在yml中配置");
        }
        return redisConnectionFactory;
    }

    public static RedisTemplate<?, ?> getRedisTemplate(String dbName) {
        RedisTemplate<?, ?> redisTemplate = templates.get(dbName);
        if (redisTemplate == null) {
            redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(getRedisConnectionFactory(dbName));
            redisTemplate.afterPropertiesSet();
            templates.put(dbName, redisTemplate);
        }
        return redisTemplate;
    }

    public static Map<String, RedisConnectionFactory> getRedisConnectionFactories() {
        return redisConnectionFactories;
    }

    public static Map<String, RedisTemplate<?, ?>> getTemplates() {
        return templates;
    }

    @SneakyThrows
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof RedisRepositoryFactoryBean) {
            RedisRepositoryFactoryBean<?, ?, ?> realBean = (RedisRepositoryFactoryBean<?, ?, ?>) bean;
            RD annotation = realBean.getObjectType().getAnnotation(RD.class);
            if (annotation != null) {
                RedisKeyValueAdapter adapter = new RedisKeyValueAdapter(getRedisTemplate(annotation.value()));
                RedisMappingContext mappingContext = new RedisMappingContext();
                RedisKeyValueTemplate redisKeyValueTemplate = new RedisKeyValueTemplate(adapter, mappingContext);
                RedisRepositoryFactory factory = new RedisRepositoryFactory(redisKeyValueTemplate);
                return factory.getRepository(realBean.getObjectType());
            }
        }
        return bean;
    }
}
